/*
 *@Type SocketServerHandler.java
 * @Desc
 * @Author urmsone urmsone@163.com
 * @date 2024/6/13 12:50
 * @version
 */
package controller;

import dto.ActionDTO;
import dto.ActionTypeEnum;
import dto.RespDTO;
import dto.RespStatusTypeEnum;
import service.NormalStore;
import service.Store;
import utils.LoggerUtil;

import java.io.*;
import java.net.Socket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//构造函数接收一个Socket对象和一个Store对象。Socket对象代表与客户端通信的网络连接，而Store对象则用于存储和检索数据。
public class SocketServerHandler implements Runnable {
    private final Logger LOGGER = LoggerFactory.getLogger(SocketServerHandler.class);
    private Socket socket;
    private Store store;

    public SocketServerHandler(Socket socket, Store store) {
        this.socket = socket;
        this.store = store;
    }
//    SocketServerHandler实例被线程调用时执行，用于处理客户端通过Socket发送的请求。
    @Override
    public void run() {
        try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
            System.out.println("客户端已连接");
            // 接收序列化对象
            ActionDTO dto = (ActionDTO) ois.readObject();
            LoggerUtil.debug(LOGGER, "[处理请求][ActionDTO]: {}", dto.toString());
            System.out.println("" + dto.toString());
            System.out.println();

            // 处理命令逻辑(TODO://改成可动态适配的模式)
// 对于GET请求，从store中获取与ActionDTO中的key相关联的值，然后构建一个RespDTO对象作为响应，并通过ObjectOutputStream将其写回到客户端。
            if (dto.getType() == ActionTypeEnum.GET) {
                String value = this.store.get(dto.getKey());
                LoggerUtil.debug(LOGGER, "[服务端处理get][run]: {}", "获取 action resp" + dto.toString());
                try {
                    if (value == null) {
                        RespDTO resp = new RespDTO(RespStatusTypeEnum.FAIL, "没有该数据");
                        oos.writeObject(resp);
                    } else {
                        RespDTO resp = new RespDTO(RespStatusTypeEnum.SUCCESS, value);
                        oos.writeObject(resp);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println();

//                每次处理完请求后，都会使用oos.flush()来确保所有输出缓冲区的数据都被发送出去。
                oos.flush();
            }
            if (dto.getType() == ActionTypeEnum.SET) {
//    对于SET请求，使用ActionDTO中的key和value更新store中的数据，然后构建一个RespDTO对象作为成功响应。
                this.store.set(dto.getKey(), dto.getValue());

                LoggerUtil.debug(LOGGER, "[服务端处理set][run]: {}", "设置请求" + dto.toString());
                RespDTO resp = new RespDTO(RespStatusTypeEnum.SUCCESS, "设置成功");
                System.out.println("服务端的setresp"+resp);
                System.out.println();
                oos.writeObject(resp);
                oos.flush();
            }
            if (dto.getType() == ActionTypeEnum.RM) {
                String keyToRemove = dto.getKey();
                System.out.println("需要删除的key: " + keyToRemove);
                System.out.println();
                // 调用 store 中的 rm 方法进行删除
                String Value = this.store.rm(keyToRemove);

                LoggerUtil.debug(LOGGER, "[服务端处理删除请求][run]: {}", "删除请求" + dto.toString());
                try {
                    if (Value != null) {
                        // 删除成功的情况下返回成功响应
                        RespDTO resp = new RespDTO(RespStatusTypeEnum.SUCCESS, "删除成功");
                        oos.writeObject(resp);
                        System.out.println("服务端的RM resp响应: " + resp);
                        System.out.println();
                    } else {
                        // 删除失败的情况下返回失败响应
                        RespDTO resp = new RespDTO(RespStatusTypeEnum.FAIL, "删除失败，没有找到对应的数据");
                        oos.writeObject(resp);
                        System.out.println("服务端的RM resp响应: " + resp);
                        System.out.println();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                oos.flush();
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
